#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <error.h>
#include <pthread.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>

#define PORT 1077
#define TCP_BUFF 1024
#define RTP_BUFF 1024 * 64

int client_fd;
struct thread_param_struct
{
    int client_fd;
    char tcp_buf[TCP_BUFF];
    char rtp_buf[RTP_BUFF];
    int rtp_reader_index;
    int rtp_write_index;
    int is_complete;
    size_t remain_to_read;
};
//数组copy，从src往dest复制len个char数据
int copy_byte_arr(char src[], char dest[], size_t src_index, size_t dest_index, size_t len)
{
    for (size_t i = 0; i < len; i++)
    {
        dest[dest_index + i] = src[src_index + i];
    }
}
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
    struct thread_param_struct *bd = (struct thread_param_struct *)opaque;

    int size;
    //如果rtp_buf里面有数据，为了保证下面的代码一致，节约开发时间，从rtp_buf写入tcp_buf,不要从socket读了
    if (bd->rtp_write_index > bd->rtp_reader_index)
    {
        memset(bd->tcp_buf, 0, sizeof(bd->tcp_buf));
        if (bd->remain_to_read > 0)
        {
            size = read(bd->client_fd, bd->tcp_buf, bd->remain_to_read);
            if (size == 0)
            {
                printf("client closed\n");
                close(bd->client_fd);
                pthread_exit(0);
            }

            //把读到的字节写入到rtp_buf
            copy_byte_arr(bd->tcp_buf, bd->rtp_buf, 0, bd->rtp_write_index, size);
            bd->rtp_write_index += size;
            bd->remain_to_read = 0;
        }

        size = bd->rtp_write_index - bd->rtp_reader_index;
        copy_byte_arr(bd->rtp_buf, bd->tcp_buf, bd->rtp_reader_index, 0, size);
        bd->rtp_reader_index += size;
    }
    else
    {
        size = read(bd->client_fd, bd->tcp_buf, TCP_BUFF);
        if (size == 0)
        {
            printf("client closed\n");
            close(bd->client_fd);
            pthread_exit(0);
        }
    }

    int i;

    for (i = 0; i < size; i++)
    {
        if (bd->tcp_buf[i] == 0x30 && bd->tcp_buf[i + 1] == 0x31 && bd->tcp_buf[i + 2] == 0x63 && bd->tcp_buf[i + 3] == 0x64)
        {
            bd->is_complete = bd->tcp_buf[i + 5] >> 7;
            if (bd->is_complete)
            {
                printf("complete flag, index is %d\n", i);
            }

            //如果还存在需要读取的数据，那么就读取remain_to_read个字节数据放到rtp_buf里面
            if (bd->remain_to_read > 0)
            {
                if (size > bd->remain_to_read)
                {

                    copy_byte_arr(bd->tcp_buf, bd->rtp_buf, 0, bd->rtp_write_index, bd->remain_to_read);
                    return bd->rtp_write_index + bd->remain_to_read;
                }
                else
                {
                    //如果本次收到的tcp数据小于remain_to_read,那么继续缓存放到rtp_buf，同时增加write_index
                    copy_byte_arr(bd->tcp_buf, bd->rtp_buf, 0, bd->rtp_write_index, size);
                    bd->rtp_write_index += size;
                    return 0;
                }
            }

            int body_len = (bd->tcp_buf[i + 24] & 0xff) << 8 | ((bd->tcp_buf[i + 25] & 0xff));
            if (size >= i + 26 + body_len)
            {
                //此时就是一个完整的帧，需要给read_packet返回
                copy_byte_arr(bd->tcp_buf, buf, i + 26, 0, body_len);
                if (size - (i + 26 + body_len) > 0)
                {

                    //这次消费不玩的，放到rtp_buf缓存里面
                    copy_byte_arr(bd->tcp_buf, bd->rtp_buf, i + 26 + body_len, bd->rtp_write_index, size - (i + 26 + body_len));
                    bd->rtp_write_index += size - (i + 26 + body_len);
                }
                return body_len;
            }
            else
            {
                //不完整的帧，整个不完整帧数据暂存到rtp_buf里面
                copy_byte_arr(bd->tcp_buf, bd->rtp_buf, i, 0, size);
                bd->remain_to_read = body_len - (size - 26);
                bd->rtp_reader_index = 0;
                bd->rtp_write_index = size;
                return 0;
            }
        }
    }

    return 0;
}

void process_client(int client_fd)
{
    AVFormatContext *fmt_ctx = NULL;
    AVIOContext *avio_ctx = NULL;
    uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
    size_t buffer_size, avio_ctx_buffer_size = 2048;
    char *input_filename = NULL;
    int ret = 0;
    av_register_all();
    if (!(fmt_ctx = avformat_alloc_context()))
    {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
    if (!avio_ctx_buffer)
    {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    struct thread_param_struct t_param;
    t_param.client_fd = client_fd;

    avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                  0, &t_param, &read_packet, NULL, NULL);
    if (!avio_ctx)
    {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    fmt_ctx->pb = avio_ctx;

    ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    if (ret < 0)
    {
        fprintf(stderr, "Could not open input\n");
        goto end;
    }

    // ret = avformat_find_stream_info(fmt_ctx, NULL);
    // if (ret < 0)
    // {
    //     fprintf(stderr, "Could not find stream information\n");
    //     goto end;
    // }

    av_dump_format(fmt_ctx, 0, NULL, 0);
    //创建packet,用于存储解码前的数据
    AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));

    while (av_read_frame(fmt_ctx, packet) >= 0)
    {
        printf("got packet%s\n", packet->data);
    }


end:
    avformat_close_input(&fmt_ctx);

    /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
    if (avio_ctx)
        av_freep(&avio_ctx->buffer);
    avio_context_free(&avio_ctx);

    av_file_unmap(buffer, buffer_size);

    if (ret < 0)
    {
        fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }

    return 0;
}

int main()
{
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(struct sockaddr_in)); //清零
    server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    server_addr.sin_port = htons(PORT);
    server_addr.sin_family = AF_INET;

    //绑定地址结构到套接字描述符
    if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind error\n");
        return -1;
    }

    if (listen(listen_fd, 20) < -1)
    {
        perror("listen error\n");
    }

    while (1)
    { //接受客户端连接
        socklen_t addrlen = sizeof(struct sockaddr);
        struct sockaddr_in clientaddr; //客户端地址结构

        client_fd = accept(listen_fd, (struct sockaddr *)&clientaddr, &addrlen);

        if (client_fd < 0)
        {
            perror("accept error");
            return -1;
        }
        printf("accept success\n");

        pthread_t pid;

        if (pthread_create(&pid, NULL, process_client, client_fd) < 0)
        {
            printf("pthread create error\n");
        }
    }
    close(listen_fd);
}